// MAIN CONFIGURATION ///////////////////////
/////////////////////////////////////////////

/**
 * @fileOverview Classes, methods & helpers function to call easily Facebook API, all data are store in Backbone.model/Backbone.collection.
 * @name fb-api-backbone
 * @author Thibaut MAREILLE
 */

/**
* @namespace facebook
**/
var facebook = {
	/**
	* @namespace Events
	*/
	Events:{},
	/**
	* @namespace Models
	*/
	Models: {},
	/**
	* @namespace Collections
	*/
	Collections: {}
};

// Events
_.extend(facebook, Backbone.Events);

// GRAPH API UNIQUE URL /////////////////////
/////////////////////////////////////////////

var graph = "https://graph.facebook.com";

// EVENTS ///////////////////////////////////
/////////////////////////////////////////////

/** facebook.Events.COMPLETE
* @memberOf facebook
* @memberOf Events
*/
facebook.Events.COMPLETE = "complete";
/** facebook.Events.ERROR
* @memberOf facebook
* @memberOf Events
*/
facebook.Events.ERROR = "error";
/** facebook.Events.SET_STATUT_MESSAGE_COMPLETE
* @memberOf facebook
* @memberOf Events
*/
facebook.Events.SET_STATUT_MESSAGE_COMPLETE = "setStatutMessageComplete";
/** facebook.Events.SET_STATUT_MESSAGE_ERROR
* @memberOf facebook
* @memberOf Events
*/
facebook.Events.SET_STATUT_MESSAGE_ERROR = "setStatutMessageError";
/** facebook.Events.SHARE_COMPLETE
* @memberOf facebook
* @memberOf Events
*/
facebook.Events.SHARE_COMPLETE = "shareComplete";
/** facebook.Events.SHARE_ERROR
* @memberOf facebook
* @memberOf Events
*/
facebook.Events.SHARE_ERROR = "shareError";
/** facebook.Events.INVITE_COMPLETE
* @memberOf facebook
* @memberOf Events
*/
facebook.Events.INVITE_COMPLETE = "inviteComplete";
/** facebook.Events.INVITE_ERROR
* @memberOf facebook
* @memberOf Events
*/
facebook.Events.INVITE_ERROR = "inviteError";
/** facebook.Events.ALBUM_COMPLETE
* @memberOf facebook
* @memberOf Events
*/
facebook.Events.ALBUM_COMPLETE = "albumComplete";
/** facebook.Events.ALBUM_ERROR
* @memberOf facebook
* @memberOf Events
*/
facebook.Events.ALBUM_ERROR = "albumError";
/** facebook.Events.UPLOAD_PICTURE_COMPLETE
* @memberOf facebook
* @memberOf Events
*/
facebook.Events.UPLOAD_PICTURE_COMPLETE = "uploadPictureComplete";
/** facebook.Events.UPLOAD_PICTURE_ERROR
* @memberOf facebook
* @memberOf Events
*/
facebook.Events.UPLOAD_PICTURE_ERROR = "uploadPictureError";

// TOKEN ////////////////////////////////////
/////////////////////////////////////////////

facebook.setToken = function(token){

	facebook.token = token;

}

facebook.getToken = function(){

	return facebook.token;
}

// HELPERS //////////////////////////////////
/////////////////////////////////////////////

// Sync method (graph API Only)
var Sync = function(method, model, options) {

	var url = (this.url instanceof Function) ? this.url() : this.url;
	var params = {};
	var token = facebook.getToken();
	if( token ){
		if( url instanceof Object) { url["access_token"] = token; }
		else { url += ( url.search(/\?/) > -1 ) ? "&access_token="+ token : "?access_token="+ token; }
	}

	// Sur Facebook
	if (!facebook.isLocal) {

		FB.api(url, function( response ) {
			var data = response.data || response;
			options.success( data );
		});

	// En local
	} else {

		$.ajax({url: url}).done(function(response){
			var data = response.data || response;
			options.success( data );
		});

	}

};

/////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////ME ///////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////

/** Return information of current user
 * @memberOf facebook
 * @memberOf Models
 * @constructor
 * @fires facebook.Events.COMPLETE
 * @fires facebook.Events.ERROR
 * @example
 * facebook.me = new facebook.Models.Me();
 * facebook.me.on(facebook.Events.COMPLETE,this.onComplete);
 * facebook.me.on(facebook.Events.ERROR,this.onError);
 * @example
 * onError:function(){console.log("error");}
 * onComplete:function(){console.log(facebook.me);}
 */

facebook.Models.Me = Backbone.Model.extend({
	url : graph + "/me",
	sync: Sync,
	defaults : {},
	/*options : {
		autosync: true,
	},*/
	initialize: function(){
		var self = this;
		this.fetch({success: this.onComplete,error: this.onError});
	},

	change:function(){

		// square, small, normal, large
		this.set({picture:facebook.getPicture(this.get("id"),"normal")});

	},

	onError:function(context){context.trigger(facebook.Events.ERROR);},
	onComplete:function(context){context.trigger(facebook.Events.COMPLETE);}


});

/////////////////////////////////////////////////////////////////////////////////
//////////////////////////////PERMISSIONS ///////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////

/** Return permissions of current user
 * @memberOf facebook
 * @memberOf Models
 * @constructor
 * @fires facebook.Events.COMPLETE
 * @fires facebook.Events.ERROR
 * @example
 * facebook.permissions = new facebook.Models.Permissions();
 * facebook.permissions.on(facebook.Events.COMPLETE,this.onComplete);
 * facebook.permissions.on(facebook.Events.ERROR,this.onError);
 * @example
 * onError:function(){console.log("error");}
 * onComplete:function(){console.log(facebook.permissions);}
 */

facebook.Models.Permissions = Backbone.Model.extend({

	url : graph + "/me/permissions",
		sync: Sync,
		defaults : {},
		options : {

		},
		initialize: function(){
			var self = this;
			this.fetch({success: this.onComplete,error: this.onError});
		},
		parse:function(response){

			return response[0];

		},

		onError:function(context){context.trigger(facebook.Events.ERROR);},
		onComplete:function(context){context.trigger(facebook.Events.COMPLETE);}

});

/////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////FRIENDS ////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////

facebook.Models.Friend = Backbone.Model.extend({

	defaults : {},

	initialize:function(){

		this.set({picture:facebook.getPicture(this.get("id"),"square")});

	}

});

/** Return friend(s) of current user
 * @memberOf facebook
 * @memberOf Collections
 * @constructor
 * @fires facebook.Events.COMPLETE
 * @fires facebook.Events.ERROR
 * @example
 * facebook.friends = new facebook.Collections.Friends();
 * facebook.friends.on(facebook.Events.COMPLETE,this.onComplete);
 * facebook.friends.on(facebook.Events.ERROR,this.onError);
 * @example
 * onError:function(){console.log("error");}
 * onComplete:function(){console.log(facebook.friends);}
 */

facebook.Collections.Friends = Backbone.Collection.extend({
	model: facebook.Models.Friend,
	url : graph + "/me/friends",
	sync: Sync,
	defaults : {},
	options : {

	},
	initialize: function(){
		var self = this;
		this.fetch({success: this.onComplete,error: this.onError});
	},

	onError:function(context){context.trigger(facebook.Events.ERROR);},
	onComplete:function(context){context.trigger(facebook.Events.COMPLETE);}

});


/////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////FEED ////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////

facebook.Models.Feed = Backbone.Model.extend({

	defaults : {},

	initialize:function(){

	//console.log("facebook.Models.Feed init");

	}

});

facebook.Collections.Feed = Backbone.Collection.extend({
	model: facebook.Models.Feed,
	url : graph + "/me/feed",
	sync: Sync,
	defaults : {},
	options : {

	},
	initialize: function(){
		var self = this;
		this.fetch({success: this.onComplete,error: this.onError});
	},

	change:function(){

		//console.log("change collection feed");

	},

	onError:function(context){context.trigger(facebook.Events.ERROR);},
	onComplete:function(context){context.trigger(facebook.Events.COMPLETE);}

});

////////////////////////////////////////////////////////////////////////////////
///////////////////////////////ALBUMS///////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

facebook.Models.Album = Backbone.Model.extend({

	sync: Sync,
	defaults : {},

	initialize:function(){

		this.url = graph+"/"+this.id+"/photos";
		this.fetch({success: this.onComplete,error: this.onError});

	},

	change:function(){

	},

	onError:function(context){context.trigger(facebook.Events.ERROR);},
	onComplete:function(context){

		var obj = [];

		if (context.get("count") && context.get("count") > 0) {

			for (var i=0;i<context.get("count");i++) {
				if (context.get(i)) obj.push(context.get(i));
			}

			context.set({data:obj});
			if (context.get("cover_photo")) context.set({cover_photo_url:facebook.getPicture(context.get("cover_photo"),"thumbnail")});

		} else {

			context.set({data:obj});

		}

		context.collection.dispatch();

	}

});

/** Return album(s) of current user
 * @memberOf facebook
 * @memberOf Collections
 * @constructor
 * @fires facebook.Events.COMPLETE
 * @fires facebook.Events.ERROR
 * @example
 * facebook.albums = new facebook.Collections.Albums();
 * facebook.albums.on(facebook.Events.COMPLETE,this.onComplete);
 * facebook.albums.on(facebook.Events.ERROR,this.onError);
 * @example
 * onError:function(){console.log("error");}
 * onComplete:function(){console.log(facebook.albums);}
 */

facebook.Collections.Albums = Backbone.Collection.extend({

	url : graph + "/me/albums",
	model:facebook.Models.Album,
	sync: Sync,
	defaults : {},
	options : {},
	initialize: function(){
		var self = this;
		this.modelLoaded = 0;
		this.fetch({success: this.onComplete,error: this.onError});
	},

	dispatch:function(){

		this.modelLoaded++;
		if (this.modelLoaded == this.length) this.trigger(facebook.Events.COMPLETE);
	},

	onError:function(context){context.trigger(facebook.Events.ERROR);},
	onComplete:function(context){}

});

////////////////////////////////////////////////////////////////////////////////
///////////////////////////////HELPERS//////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////


facebook.getPicture = function(uid,type){

	if (!type) type = "normal";
	return "https://graph.facebook.com/"+uid+"/picture?type="+type;

}

////////////////////////////////////////////////////////////////////////////////
/////////////////////////SET STATUT MESSAGE/////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

/** Post a message on your timeline.
* @function setStatutMessage
* @memberOf facebook
* @name setStatutMessage
* @param {object} data
* @fires facebook.Events.SET_STATUT_MESSAGE_COMPLETE
* @fires facebook.Events.SET_STATUT_MESSAGE_ERROR
* @example
* var data = {
* message:"Sample text",
* picture:"http://greenlime.fr/images/samplePicture.png",
* link:"http://www.greenlime.fr",
* name:"Sample name",
* caption:"Send by Application",
* description:"Sample Description",
* source:null,
* place:null,
* tags:null
* };
* facebook.setStatutMessage(data);
* facebook.on(facebook.Events.SET_STATUT_MESSAGE_COMPLETE, onComplete);
* facebook.on(facebook.Events.SET_STATUT_MESSAGE_ERROR, onError);
* @example
* onError:function(){console.log("error");}
* onComplete:function(){console.log("statut message send");}
*/

facebook.setStatutMessage = function(data){

	// Check Permissions : publish_stream
	if (facebook.permissions.get("publish_stream") == 1) {

		var url = graph + "/me/feed";

		var token = facebook.getToken();
		if( token ){
			if( url instanceof Object) { url["access_token"] = token; }
			else { url += ( url.search(/\?/) > -1 ) ? "&access_token="+ token : "?access_token="+ token; }
		}

		if (!facebook.isLocal) {


				FB.api(url, 'post', {
				message: data.message,
				picture:data.picture,
				link:data.link,
				name:data.name,
				caption:data.caption,
				description:data.description,
				source:data.source,
				place:data.place,
				tags:data.tags
				}, function(response) {
				  if (!response || response.error) {
					facebook.trigger(facebook.Events.SET_STATUT_MESSAGE_ERROR,response);
				  } else {
					facebook.trigger(facebook.Events.SET_STATUT_MESSAGE_COMPLETE,response);
				  }
				});

		} else {

			$.ajax({
			type: "POST",
			url: url,
			data: {
			message: data.message,
			picture:data.picture,
			link:data.link,
			name:data.name,
			caption:data.caption,
			description:data.description,
			source:data.source,
			place:data.place,
			tags:data.tags
			}
			}).done(function( response ) {
				if (!response || response.error) {
					facebook.trigger(facebook.Events.SET_STATUT_MESSAGE_ERROR,response);
				} else {
					facebook.trigger(facebook.Events.SET_STATUT_MESSAGE_COMPLETE,response);
				}
			});

		}

	} else {

		console.log("facebook.permissions doesn't exist or you don't have a publish stream permission");

	}

}

////////////////////////////////////////////////////////////////////////////////
////////////////////////////CREATE ALBUM////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

/** Create an album.
* @function createAlbum
* @memberOf facebook
* @name createAlbum
* @param {object} data
* @fires facebook.Events.ALBUM_COMPLETE
* @fires facebook.Events.ALBUM_ERROR
* @example
* var data = {
* title:"Sample title",
* description:"Sample description"
* };
*
* facebook.createAlbum(data);
* facebook.on(facebook.Events.ALBUM_COMPLETE, onComplete);
* facebook.on(facebook.Events.ALBUM_ERROR, onError);
* @example
* onError:function(){console.log("error");}
* onComplete:function(){console.log("album created");}
*/

facebook.createAlbum = function(data){

	if (facebook.permissions.get("publish_stream") == 1) {

		var url = graph + "/me/albums";

		var token = facebook.getToken();
		if( token ){
			if( url instanceof Object) { url["access_token"] = token; }
			else { url += ( url.search(/\?/) > -1 ) ? "&access_token="+ token : "?access_token="+ token; }
		}

		if (!facebook.isLocal) {


				FB.api(url, 'post', {
				name:data.title,
				message:data.description
				}, function(response) {
				  if (!response || response.error) {
					facebook.trigger(facebook.Events.ALBUM_ERROR,response);
				  } else {
					facebook.lastCreateAlbumId = response.id;
					facebook.trigger(facebook.Events.ALBUM_COMPLETE,response);
				  }
				});

		} else {

			$.ajax({
			type: "POST",
			url: url,
			data: {
				name:data.title,
				message:data.description
			}
			}).done(function( response ) {
				if (!response || response.error) {
					facebook.trigger(facebook.Events.ALBUM_ERROR,response);
				} else {
					facebook.lastCreateAlbumId = response.id;
					facebook.trigger(facebook.Events.ALBUM_COMPLETE,response);
				}
			});

		}



	} else {

		console.log("facebook.createAlbum doesn't work because you don't have a publish permission");

	}

}

////////////////////////////////////////////////////////////////////////////////
////////////////////////////POST PHOTO FEED/////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

/** Upload a photo on your timeline or album specified.
* @function uploadPicture
* @memberOf facebook
* @name uploadPicture
* @param {object} data
* @fires facebook.Events.UPLOAD_PICTURE_COMPLETE
* @fires facebook.Events.UPLOAD_PICTURE_ERROR
* @example
* var data = {
* src:"Sample url",
* description:"Sample description",
* albumId:"albumID"
* };
*
* facebook.uploadPicture(data);
* facebook.on(facebook.Events.UPLOAD_PICTURE_COMPLETE, onComplete);
* facebook.on(facebook.Events.UPLOAD_PICTURE_ERROR, onError);
* @example
* onError:function(){console.log("error");}
* onComplete:function(){console.log("picture uploaded");}
*/

facebook.uploadPicture = function (data){

	if (facebook.permissions.get("publish_stream") == 1) {

		var url = graph + "/me/photos";
		if (data.albumId && data.albumId != undefined) url = graph + "/"+data.albumId+"/photos";

		var token = facebook.getToken();
		if( token ){
			if( url instanceof Object) { url["access_token"] = token; }
			else { url += ( url.search(/\?/) > -1 ) ? "&access_token="+ token : "?access_token="+ token; }
		}

		if (!facebook.isLocal) {


				FB.api(url, 'post', {
				url:data.src,
				message:data.description
				}, function(response) {
				  if (!response || response.error) {
					facebook.trigger(facebook.Events.UPLOAD_PICTURE_ERROR,response);
				  } else {
					facebook.trigger(facebook.Events.UPLOAD_PICTURE_COMPLETE,response);
				  }
				});

		} else {

			$.ajax({
			type: "POST",
			url: url,
			data: {
				url:data.src,
				message:data.description
			}
			}).done(function( response ) {
				if (!response || response.error) {
					facebook.trigger(facebook.Events.UPLOAD_PICTURE_ERROR,response);
				} else {
					facebook.trigger(facebook.Events.UPLOAD_PICTURE_COMPLETE,response);
				}
			});

		}



	} else {

		console.log("facebook.uploadPicture doesn't work because you don't have a publish permission");

	}

}

////////////////////////////////////////////////////////////////////////////////
/////////////////////////SHARE WITH FB.UI///////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

/** Show Facebook Dialog to share application (available only on canvas Application)
* @function share
* @memberOf facebook
* @name share
* @param {object} data
* @fires facebook.Events.SHARE_COMPLETE
* @fires facebook.Events.SHARE_ERROR
* @example
* var data = {
* titre:"Facebook Dialogs",
* caption:"Reference Documentation",
* desc:"Dialogs provide a simple, consistent interface for applications to interface with users.",
* link:"https://developers.facebook.com/docs/reference/dialogs/",
* picture:"http://fbrell.com/f8.jpg"
* };
*
* facebook.share(data);
* facebook.on(facebook.Events.SHARE_COMPLETE, onComplete);
* facebook.on(facebook.Events.SHARE_ERROR, onError);
* @example
* onError:function(){console.log("error");}
* onComplete:function(){console.log("picture uploaded");}
*/

facebook.share = function(data){

	if (!facebook.isLocal) {

		FB.ui(
		  {
			method: 'feed',
			name: data.title,
			link: data.link,
			picture: data.picture,
			caption: data.caption,
			description: data.description
		  },
		  function(response) {
			if (!response || response.error) {
				facebook.trigger(facebook.Events.SHARE_ERROR,response);
			} else {
				facebook.trigger(facebook.Events.SHARE_COMPLETE,response);
			}
		  }
		);

	} else {

		alert("Share this application on your wall doesn't work on localhost");
		return false;

	}

}

////////////////////////////////////////////////////////////////////////////////
////////////////////INVITE FRIENDS WITH FB.UI///////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

/** Show Facebook Dialog to invite friends (available only on canvas Application)
* @function invite
* @memberOf facebook
* @name invite
* @param {object} data
* @fires facebook.Events.INVITE_COMPLETE
* @fires facebook.Events.INVITE_ERROR
* @example
* var data = {
* msg:"A message"
* };
*
* facebook.invite(data);
* facebook.on(facebook.Events.INVITE_COMPLETE, onComplete);
* facebook.on(facebook.Events.INVITE_ERROR, onError);
* @example
* onError:function(){console.log("error");}
* onComplete:function(){console.log("invitation send");}
*/

facebook.invite = function(data){

	if (!facebook.isLocal) {

		FB.ui({method: 'apprequests',
		  message: data.msg
		},
		  function(response) {
			if (!response || response.error) {
			facebook.trigger(facebook.Events.INVITE_ERROR,response);
			} else {
			facebook.trigger(facebook.Events.INVITE_COMPLETE,response);
			}
		  }
		);

	} else {

		alert("Invite Friends doesn't work on localhost");
		return false;

	}

}
